package vip.liux.backend.application.serviceImpl.coupon;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import vip.liux.application.dots.PagedResultDto;
import vip.liux.backend.application.service.coupon.*;
import vip.liux.backend.infrastructure.code.BizCodeGenerator;
import vip.liux.contracts.models.coupon.Coupon;
import vip.liux.contracts.models.coupon.UserCouponDomainService;
import vip.liux.contracts.repositories.coupon.CouponRepository;
import vip.liux.contracts.shared.enums.Status;
import vip.liux.contracts.shared.enums.coupon.CouponType;
import vip.liux.contracts.shared.enums.coupon.UseScope;
import vip.liux.contracts.shared.enums.coupon.UseType;
import vip.liux.contracts.shared.value.ReceivedRecord;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static vip.liux.application.PageKit.toPage;

/**
 * 优惠券服务实现类
 * 负责处理与优惠券相关的应用层逻辑
 */
@Service
public class CouponServiceImpl implements CouponService {
    private final CouponRepository couponRepository;
    private final UserCouponDomainService userCouponDomainService;
    private final BizCodeGenerator codeGenerator;

    public CouponServiceImpl(CouponRepository couponRepository, UserCouponDomainService userCouponDomainService, BizCodeGenerator codeGenerator) {
        this.couponRepository = couponRepository;
        this.userCouponDomainService = userCouponDomainService;
        this.codeGenerator = codeGenerator;
    }

    private CouponChecker preCouponChecks = new DefaultPreCouponCheck();
    private CouponChecker postCouponChecks = coupon -> {
    };

    /**
     * 创建优惠券
     *
     * @param createCouponDto 创建优惠券的数据传输对象
     * @return 创建的优惠券数据传输对象
     */
    @Override
    public CouponDto create(CreateCouponDto createCouponDto) {
        // 将 Dto 转换为领域对象
        Coupon coupon = AutoMapperProfile.INSTANCE.toCoupon(createCouponDto);

        // 执行创建前的校验逻辑
        this.preCouponChecks.check(coupon);
        coupon.setCouponNo(codeGenerator.generateCouponNo());
        coupon.setStatus(Status.ENABLED);

        // 执行创建后的校验逻辑
        this.postCouponChecks.check(coupon);

        // 保存优惠券并返回 Dto
        coupon = couponRepository.save(coupon);
        return AutoMapperProfile.INSTANCE.toCouponDto(coupon, Map.of(coupon.getCouponNo(), ReceivedRecord.empty(coupon.getCouponNo())));
    }

    /**
     * 查询优惠券
     *
     * @param input 查询条件
     * @return 分页的优惠券数据传输对象
     */
    @Override
    public PagedResultDto<CouponDto> query(QueryCouponDto input) {
        // 分页查询优惠券
        Page<Coupon> page = couponRepository.findByPage(
                input.getCouponName(),
                input.getCouponType(),
                input.getStatus(),
                input.getReceiveStart(),
                input.getReceiveEnd(),
                toPage(input)
        );
        List<Coupon> list = page.getContent();

        // 获取优惠券领取记录
        Map<String, ReceivedRecord> record = userCouponDomainService.getReceivedRecords(
                list.stream().map(Coupon::getCouponNo).collect(Collectors.toSet())
        );

        // 转换为 Dto 并返回
        return new PagedResultDto<>(list.stream().map(c -> AutoMapperProfile.INSTANCE.toCouponDto(c, record)).toList(), page.getTotalElements());
    }

    /**
     * 获取优惠券详情
     *
     * @param id 优惠券 ID
     * @return 优惠券数据传输对象
     */
    @Override
    public CouponDto detail(Long id) {
        Optional<Coupon> optional = couponRepository.findById(id);
        return buildCouponDto(optional);
    }

    /**
     * 获取优惠券详情
     *
     * @param couponNo 优惠券编号
     * @return 优惠券数据传输对象
     */
    @Override
    public CouponDto detail(String couponNo) {
        Optional<Coupon> optional = couponRepository.findByCouponNo(couponNo);
        return buildCouponDto(optional);
    }

    /**
     * 构建优惠券数据传输对象
     *
     * @param optional 优惠券对象的 Optional 包装
     * @return 优惠券数据传输对象
     */
    private CouponDto buildCouponDto(Optional<Coupon> optional) {
        if (optional.isEmpty()) return null;
        Coupon coupon = optional.get();
        Map<String, ReceivedRecord> record = userCouponDomainService.getReceivedRecords(Set.of(coupon.getCouponNo()));
        return AutoMapperProfile.INSTANCE.toCouponDto(coupon, record);
    }

    /**
     * 停用优惠券
     *
     * @param id 优惠券 ID
     */
    @Override
    public void disable(Long id) {
        couponRepository.findById(id).ifPresent(coupon -> {
            coupon.setStatus(Status.DISABLED);
            couponRepository.save(coupon);
        });
    }

    /**
     * 查询可用优惠券
     *
     * @return 可用优惠券数据传输对象列表
     */
    @Override
    public List<ShopCouponDto> queryAvailableCoupons() {
        // 查询可用优惠券
        List<Coupon> list = couponRepository.findQueryAvailableCoupons();

        // 获取优惠券领取记录
        Map<String, ReceivedRecord> record = userCouponDomainService.getReceivedRecords(
                list.stream().map(Coupon::getCouponNo).collect(Collectors.toSet())
        );

        // 转换为 Dto 并返回
        return list.stream().map(c -> AutoMapperProfile.INSTANCE.toShopCouponDto(c, record)).toList();
    }

    /**
     * 设置自定义的优惠券创建前校验逻辑
     *
     * @param preCouponChecks 自定义校验逻辑
     */
    @Autowired(required = false)
    public void setPreCouponChecks(CouponChecker preCouponChecks) {
        this.preCouponChecks = preCouponChecks;
    }

    /**
     * 设置自定义的优惠券创建后校验逻辑
     *
     * @param postCouponChecks 自定义校验逻辑
     */
    @Autowired(required = false)
    public void setPostCouponChecks(CouponChecker postCouponChecks) {
        this.postCouponChecks = postCouponChecks;
    }

    /**
     * 默认的优惠券校验逻辑
     */
    private static class DefaultPreCouponCheck implements CouponChecker {
        @Override
        public void check(Coupon coupon) {
            // 校验折扣优惠券的折扣值
            if (coupon.getCouponType() == CouponType.DISCOUNT && Objects.isNull(coupon.getDiscount())) {
                throw new IllegalArgumentException("折扣优惠券必须设置折扣");
            }
            // 校验立减优惠券的金额
            if (coupon.getCouponType() == CouponType.REDUCTION && Objects.isNull(coupon.getAmount())) {
                throw new IllegalArgumentException("立减优惠券必须设置满减金额");
            }
            // 校验满金额可用的门槛金额
            if (coupon.getUseType() == UseType.FULL_AMOUNT && Objects.isNull(coupon.getFull())) {
                throw new IllegalArgumentException("满金额可用必须设置门槛金额");
            }
            // 校验使用时间范围
            if (coupon.getUseStart().isAfter(coupon.getUseEnd())) {
                throw new IllegalArgumentException("使用开始时间不能晚于结束时间");
            }
            // 校验领取时间范围
            if (coupon.getReceiveStart().isAfter(coupon.getReceiveEnd())) {
                throw new IllegalArgumentException("领取开始时间不能晚于结束时间");
            }
            // 校验领取开始时间
            if (coupon.getReceiveStart().isBefore(LocalDateTime.now())) {
                throw new IllegalArgumentException("领取开始时间不能早于当前时间");
            }
            // 校验指定商品优惠券的商品配置
            if (coupon.getUseScope() == UseScope.PARTIAL_PRODUCTS && coupon.getScopeConfig().isEmpty()) {
                throw new IllegalArgumentException("指定商品优惠券必须设置商品");
            }
        }
    }
}